/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 * http://www.gnu.org/copyleft/gpl.html
 */
package l1j.server.server.model;

import java.util.Random;
import java.util.logging.Logger;

import l1j.server.Config;
import l1j.server.server.ActionCodes;
import l1j.server.server.model.Instance.L1ItemInstance;
import l1j.server.server.model.Instance.L1NpcInstance;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.model.Instance.L1PetInstance;
import l1j.server.server.model.Instance.L1SummonInstance;
import l1j.server.server.model.gametime.L1GameTimeClock;
import l1j.server.server.model.poison.L1DamagePoison;
import l1j.server.server.model.poison.L1ParalysisPoison;
import l1j.server.server.model.poison.L1SilencePoison;
import l1j.server.server.serverpackets.S_AttackMissPacket;
import l1j.server.server.serverpackets.S_AttackPacket;
import l1j.server.server.serverpackets.S_AttackStatus;
import l1j.server.server.serverpackets.S_CharVisualUpdate;
import l1j.server.server.serverpackets.S_DeleteInventoryItem;
import l1j.server.server.serverpackets.S_DoActionGFX;
import l1j.server.server.serverpackets.S_OwnCharStatus;
import l1j.server.server.serverpackets.S_ServerMessage;
import l1j.server.server.serverpackets.S_SkillSound;
import l1j.server.server.serverpackets.S_UseArrowSkill;
import l1j.server.server.serverpackets.S_UseAttackSkill;
import l1j.server.server.types.Point;
import static l1j.server.server.model.skill.L1SkillId.*;

public class L1Attack {
	private static Logger _log = Logger.getLogger(L1Attack.class.getName());

	private L1PcInstance _pc = null;

	private L1Character _target = null;

	private L1PcInstance _targetPc = null;

	private L1NpcInstance _npc = null;

	private L1NpcInstance _targetNpc = null;

	private final int _targetId;

	private int _targetX;

	private int _targetY;

	private int _statusDamage = 0;

	private static final Random _random = new Random();

	private int _hitRate = 0;

	private int _calcType;

	private static final int PC_PC = 1;

	private static final int PC_NPC = 2;

	private static final int NPC_PC = 3;

	private static final int NPC_NPC = 4;

	private boolean _isHit = false;

	private int _damage = 0;

	private int _drainMana = 0;

	private int _attckGrfxId = 0;

	private int _attckActId = 0;

	// 攻撃者がプレイヤーの場合の武器情報
	private L1ItemInstance weapon = null;

	private int _weaponId = 0;

	private int _weaponType = 0;

	private int _weaponAddHit = 0;

	private int _weaponAddDmg = 0;

	private int _weaponSmall = 0;

	private int _weaponLarge = 0;

	private int _weaponBless = 1;

	private int _weaponEnchant = 0;

	private int _weaponMaterial = 0;

	private L1ItemInstance _arrow = null;

	private L1ItemInstance _sting = null;

	private boolean _diceDaggerEffect = false;

	private int _diceDaggerDamage = 0;

	private int _leverage = 10; // 1/10倍で表現する。

	public void setLeverage(int i) {
		_leverage = i;
	}

	private int getLeverage() {
		return _leverage;
	}

	// 攻撃者がプレイヤーの場合のステータスによる補正
	private static final int[] strHit = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
			-1, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8,
			8, 8, 9, 9, 9, 10, 10, 10, 10, 10 };

	private static final int[] dexHit = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
			0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
			15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 };

	private static final int[] strDmg = new int[128];

	static {
		// ＳＴＲダメージ補正
		int dmg = -6;
		for (int str = 0; str <= 22; str++) { // ０～２２は２毎に＋１
			if (str % 2 == 1) {
				dmg++;
			}
			strDmg[str] = dmg;
		}
		for (int str = 23; str <= 28; str++) { // ２３～２８は３毎に＋１
			if (str % 3 == 2) {
				dmg++;
			}
			strDmg[str] = dmg;
		}
		for (int str = 29; str <= 32; str++) { // ２９～３２は２毎に＋１
			if (str % 2 == 1) {
				dmg++;
			}
			strDmg[str] = dmg;
		}
		for (int str = 33; str <= 39; str++) { // ３３～３９は１毎に＋１
			dmg++;
			strDmg[str] = dmg;
		}
		for (int str = 40; str <= 46; str++) { // ４０～４６は１毎に＋２
			dmg += 2;
			strDmg[str] = dmg;
		}
		for (int str = 47; str <= 127; str++) { // ４７～１２７は１毎に＋１
			dmg++;
			strDmg[str] = dmg;
		}
	}

	private static final int[] dexDmg = new int[128];

	static {
		// ＤＥＸダメージ補正
		for (int dex = 0; dex <= 14; dex++) {
			// ０～１４は０
			dexDmg[dex] = 0;
		}
		dexDmg[15] = 1;
		dexDmg[16] = 2;
		dexDmg[17] = 3;
		dexDmg[18] = 4;
		dexDmg[19] = 4;
		dexDmg[20] = 4;
		dexDmg[21] = 5;
		dexDmg[22] = 5;
		dexDmg[23] = 5;
		int dmg = 5;
		for (int dex = 24; dex <= 127; dex++) { // ２４～１２７は１毎に＋１
			dmg++;
			dexDmg[dex] = dmg;
		}
	}

	public void setActId(int actId) {
		_attckActId = actId;
	}

	public void setGfxId(int gfxId) {
		_attckGrfxId = gfxId;
	}

	public int getActId() {
		return _attckActId;
	}

	public int getGfxId() {
		return _attckGrfxId;
	}

	public L1Attack(L1Character attacker, L1Character target) {
		if (attacker instanceof L1PcInstance) {
			_pc = (L1PcInstance) attacker;
			if (target instanceof L1PcInstance) {
				_targetPc = (L1PcInstance) target;
				_calcType = PC_PC;
			} else if (target instanceof L1NpcInstance) {
				_targetNpc = (L1NpcInstance) target;
				_calcType = PC_NPC;
			}
			// 武器情報の取得
			weapon = _pc.getWeapon();
			if (weapon != null) {
				_weaponId = weapon.getItem().getItemId();
				_weaponType = weapon.getItem().getType1();
				_weaponAddHit = weapon.getItem().getHitModifier();
				_weaponAddDmg = weapon.getItem().getDmgModifier();
				_weaponSmall = weapon.getItem().getDmgSmall();
				_weaponLarge = weapon.getItem().getDmgLarge();
				_weaponBless = weapon.getItem().getBless();
				_weaponEnchant = weapon.getEnchantLevel()
						- weapon.get_durability(); // 損傷分マイナス
				_weaponMaterial = weapon.getItem().getMaterial();
				if (_weaponType == 20) { // アローの取得
					_arrow = _pc.getInventory().getArrow();
					if (_arrow != null) {
						_weaponBless = _arrow.getItem().getBless();
						_weaponMaterial = _arrow.getItem().getMaterial();
					}
				}
				if (_weaponType == 62) { // スティングの取得
					_sting = _pc.getInventory().getSting();
					if (_sting != null) {
						_weaponBless = _sting.getItem().getBless();
						_weaponMaterial = _sting.getItem().getMaterial();
					}
				}
			}
			// ステータスによる追加ダメージ補正
			if (_weaponType == 20) { // 弓の場合はＤＥＸ値参照
				_statusDamage = dexDmg[_pc.getDex()];
			} else { // それ以外はＳＴＲ値参照
				_statusDamage = strDmg[_pc.getStr()];
			}
		} else if (attacker instanceof L1NpcInstance) {
			_npc = (L1NpcInstance) attacker;
			if (target instanceof L1PcInstance) {
				_targetPc = (L1PcInstance) target;
				_calcType = NPC_PC;
			} else if (target instanceof L1NpcInstance) {
				_targetNpc = (L1NpcInstance) target;
				_calcType = NPC_NPC;
			}
		}
		_target = target;
		_targetId = target.getId();
		_targetX = target.getX();
		_targetY = target.getY();
	}

	/* ■■■■■■■■■■■■■■■■ 命中判定 ■■■■■■■■■■■■■■■■ */

	public boolean calcHit() {
		if (_calcType == PC_PC || _calcType == PC_NPC) {
			if (_weaponType == 20 && _weaponId != 190 && _arrow == null) {
				_isHit = false; // 矢がない場合はミス
			} else if (_weaponType == 62 && _sting == null) {
				_isHit = false; // スティングがない場合はミス
			} else if (!_pc.glanceCheck(_targetX, _targetY)) {
				_isHit = false; // 攻撃者がプレイヤーの場合は障害物判定
			} else if (_calcType == PC_PC) {
				_isHit = calcPcPcHit();
			} else if (_calcType == PC_NPC) {
				_isHit = calcPcNpcHit();
			}
		} else if (_calcType == NPC_PC) {
			_isHit = calcNpcPcHit();
		} else if (_calcType == NPC_NPC) {
			_isHit = calcNpcNpcHit();
		}
		return _isHit;
	}

	// ●●●● プレイヤー から プレイヤー への命中判定 ●●●●
	/*
	 * ＰＣへの命中率 ＝（PCのLv＋クラス補正＋STR補正＋DEX補正＋武器補正＋DAIの枚数/2＋魔法補正）×0.68－10
	 * これで算出された数値は自分が最大命中(95%)を与える事のできる相手側PCのAC そこから相手側PCのACが1良くなる毎に自命中率から1引いていく
	 * 最小命中率5% 最大命中率95%
	 */
	private boolean calcPcPcHit() {
		final int MIN_HITRATE = 5;

		int hitRate = _pc.getLevel();

		if (_pc.getStr() > 39) {
			hitRate += strHit[39];
		} else {
			hitRate += strHit[_pc.getStr()];
		}

		if (_pc.getDex() > 39) {
			hitRate += dexHit[39];
		} else {
			hitRate += dexHit[_pc.getDex()];
		}

		hitRate += _weaponAddHit + _pc.getHitup() + (_weaponEnchant / 2);

		if (_weaponType == 20) { // 弓
			_hitRate += _pc.getBowHitRate();
		}

		int hitAc = (int) (hitRate * 0.68 - 10) * -1;

		if (hitAc <= _targetPc.getAc()) {
			_hitRate = 95;
		} else {
			_hitRate = 95 - (hitAc - _targetPc.getAc());
		}

		if (_targetPc.hasSkillEffect(UNCANNY_DODGE)) {
			_hitRate -= 20;
		}

		if (_hitRate < MIN_HITRATE) {
			_hitRate = MIN_HITRATE;
		}

		if (_targetPc.hasSkillEffect(ABSOLUTE_BARRIER)) {
			_hitRate = 0;
		}
		if (_targetPc.hasSkillEffect(ICE_LANCE)) {
			_hitRate = 0;
		}
		if (_targetPc.hasSkillEffect(EARTH_BIND)) {
			_hitRate = 0;
		}

		int rnd = _random.nextInt(100) + 1;
		if (_weaponType == 20 && _hitRate > rnd) { // 弓の場合、ヒットした場合でもERでの回避を再度行う。
			return calcErEvasion();
		}

		return _hitRate >= rnd;
	}

	// ●●●● プレイヤー から ＮＰＣ への命中判定 ●●●●
	private boolean calcPcNpcHit() {
		// ＮＰＣへの命中率
		// ＝（PCのLv＋クラス補正＋STR補正＋DEX補正＋武器補正＋DAIの枚数/2＋魔法補正）×5－{NPCのAC×（-5）}
		_hitRate = _pc.getLevel();

		if (_pc.getStr() > 39) {
			_hitRate += strHit[39];
		} else {
			_hitRate += strHit[_pc.getStr()];
		}

		if (_pc.getDex() > 39) {
			_hitRate += dexHit[39];
		} else {
			_hitRate += dexHit[_pc.getDex()];
		}

		_hitRate += _weaponAddHit + _pc.getHitup() + (_weaponEnchant / 2);

		if (_weaponType == 20) { // 弓
			_hitRate += _pc.getBowHitRate();
		}

		_hitRate *= 5;
		_hitRate += _targetNpc.getAc() * 5;

		if (_hitRate > 95) {
			_hitRate = 95;
		} else if (_hitRate < 5) {
			_hitRate = 5;
		}
		int rnd = _random.nextInt(100) + 1;

		return _hitRate >= rnd;
	}

	// ●●●● ＮＰＣ から プレイヤー への命中判定 ●●●●
	private boolean calcNpcPcHit() {
		// ＰＣへの命中率
		// ＝（NPCのLv×2）×5－{NPCのAC×（-5）}
		_hitRate = _npc.getLevel() * 2;
		_hitRate *= 5;
		_hitRate += _targetPc.getAc() * 5;

		if (_npc instanceof L1PetInstance) { // ペットはLV1毎に追加命中+2
			_hitRate += _npc.getLevel() * 2;
		}

		_hitRate += _npc.getHitup();

		// 最低命中率をNPCのレベルに設定
		if (_hitRate < _npc.getLevel()) {
			_hitRate = _npc.getLevel();
		}

		if (_hitRate > 95) {
			_hitRate = 95;
		}

		if (_targetPc.hasSkillEffect(UNCANNY_DODGE)) {
			_hitRate -= 20;
		}

		if (_hitRate < 5) {
			_hitRate = 5;
		}

		if (_targetPc.hasSkillEffect(ABSOLUTE_BARRIER)) {
			_hitRate = 0;
		}
		if (_targetPc.hasSkillEffect(ICE_LANCE)) {
			_hitRate = 0;
		}
		if (_targetPc.hasSkillEffect(EARTH_BIND)) {
			_hitRate = 0;
		}

		int rnd = _random.nextInt(100) + 1;

		// NPCの攻撃レンジが10以上の場合で、2以上離れている場合弓攻撃とみなす
		if (_npc.getNpcTemplate().get_ranged() >= 10
				&& _hitRate > rnd
				&& _npc.getLocation().getTileLineDistance(
						new Point(_targetX, _targetY)) >= 2) {
			return calcErEvasion();
		}
		return _hitRate >= rnd;
	}

	// ●●●● ＮＰＣ から ＮＰＣ への命中判定 ●●●●
	private boolean calcNpcNpcHit() {
		int target_ac = 10 - _targetNpc.getNpcTemplate().get_ac();
		int attacker_lvl = _npc.getNpcTemplate().get_level();

		if (target_ac != 0) {
			_hitRate = (100 / target_ac * attacker_lvl); // 被攻撃者AC = 攻撃者Lv
			// の時命中率１００％
		} else {
			_hitRate = 100 / 1 * attacker_lvl;
		}

		if (_npc instanceof L1PetInstance) { // ペットはLV1毎に追加命中+2
			_hitRate += _npc.getLevel() * 2;
		}

		if (_hitRate < attacker_lvl) {
			_hitRate = attacker_lvl; // 最低命中率＝Ｌｖ％
		}
		if (_hitRate > 95) {
			_hitRate = 95; // 最高命中率は９５％
		}
		if (_hitRate < 5) {
			_hitRate = 5; // 攻撃者Lvが５未満の時は命中率５％
		}

		int rnd = _random.nextInt(100) + 1;
		return _hitRate >= rnd;
	}

	// ●●●● ＥＲによる回避判定 ●●●●
	private boolean calcErEvasion() {
		int er = _targetPc.getEr();

		int rnd = _random.nextInt(100) + 1;
		return er < rnd;
	}

	/* ■■■■■■■■■■■■■■■ ダメージ算出 ■■■■■■■■■■■■■■■ */

	public int calcDamage() {
		if (_calcType == PC_PC) {
			_damage = calcPcPcDamage();
		} else if (_calcType == PC_NPC) {
			_damage = calcPcNpcDamage();
		} else if (_calcType == NPC_PC) {
			_damage = calcNpcPcDamage();
		} else if (_calcType == NPC_NPC) {
			_damage = calcNpcNpcDamage();
		}
		return _damage;
	}

	// ●●●● プレイヤー から プレイヤー へのダメージ算出 ●●●●
	public int calcPcPcDamage() {
		int weaponMaxDamage = _weaponSmall;

		int weaponDamage = 0;
		if (_weaponType == 58 && (_random.nextInt(100) + 1) <= 33) { // クリティカルヒット
			weaponDamage = weaponMaxDamage;
			_pc.sendPackets(new S_SkillSound(_pc.getId(), 3671));
			_pc.broadcastPacket(new S_SkillSound(_pc.getId(), 3671));
		} else if (_weaponType == 0) { // 素手
			weaponDamage = 0;
		} else {
			weaponDamage = _random.nextInt(weaponMaxDamage) + 1;
		}
		if (_pc.hasSkillEffect(SOUL_OF_FLAME)) {
			if (_weaponType != 20 && _weaponType != 62) {
				weaponDamage = weaponMaxDamage;
			}
		}

		int weaponTotalDamage = weaponDamage + _weaponAddDmg + _weaponEnchant;
		if (_pc.hasSkillEffect(DOUBLE_BRAKE)
				&& (_weaponType == 54 || _weaponType == 58)) {
			if ((_random.nextInt(100) + 1) <= 33) {
				weaponTotalDamage *= 2;
			}
		}

		if (_weaponType == 54 && (_random.nextInt(100) + 1) <= 25) { // ダブルヒット
			weaponTotalDamage *= 2;
			_pc.sendPackets(new S_SkillSound(_pc.getId(), 3398));
			_pc.broadcastPacket(new S_SkillSound(_pc.getId(), 3398));
		}

		double dmg = weaponTotalDamage + _statusDamage + _pc.getDmgup();

		if (_pc.isKnight() || _pc.isDarkelf()) { // ナイト、DE
			if (_weaponType == 20 || _weaponType == 62) { // 弓、ガントトレットならクラスダメージボーナスなし
				dmg -= _pc.getBaseDmgup();
			}
		} else if (_pc.isElf()) { // エルフ
			if (_weaponType != 20 && _weaponType != 62) { // 弓、ガントトレット以外ならクラスダメージボーナスなし
				dmg -= _pc.getBaseDmgup();
			}
		}

		if (_weaponType == 20) { // 弓
			if (_arrow != null) {
				int add_dmg = _arrow.getItem().getDmgSmall();
				if (add_dmg == 0) {
					add_dmg = 1;
				}
				dmg = dmg + _random.nextInt(add_dmg) + 1;
			} else if (_weaponId == 190) { // サイハの弓
				dmg = dmg + _random.nextInt(15) + 1;
			}
		} else if (_weaponType == 62) { // ガントトレット
			int add_dmg = _sting.getItem().getDmgSmall();
			if (add_dmg == 0) {
				add_dmg = 1;
			}
			dmg = dmg + _random.nextInt(add_dmg) + 1;
		}

		dmg = calcBuffDamage(dmg);

		dmg += calcWeaponSkillDamage();

		if (_diceDaggerEffect) { // ダイスダガー
			dmg = _diceDaggerDamage;
		}

		if (_weaponType == 0) { // 素手
			dmg = (_random.nextInt(5) + 4) / 4;
		}

		dmg -= _targetPc.getDamageReductionByArmor(); // 防具によるダメージ軽減

		if (_targetPc.hasSkillEffect(REDUCTION_ARMOR)) {
			int targetPcLvl = _targetPc.getLevel();
			if (targetPcLvl < 50) {
				targetPcLvl = 50;
			}
			dmg -= (targetPcLvl - 50) / 5 + 1;
		}
		if (_targetPc.hasSkillEffect(IMMUNE_TO_HARM)) {
			dmg /= 2;
		}
		if (_targetPc.hasSkillEffect(ABSOLUTE_BARRIER)) {
			dmg = 0;
		}
		if (_targetPc.hasSkillEffect(ICE_LANCE)) {
			dmg = 0;
		}
		if (_targetPc.hasSkillEffect(EARTH_BIND)) {
			dmg = 0;
		}

		if (dmg <= 0) {
			_isHit = false;
		}

		return (int) dmg;
	}

	// ●●●● プレイヤー から ＮＰＣ へのダメージ算出 ●●●●
	private int calcPcNpcDamage() {
		int weaponMaxDamage = 0;
		if (_targetNpc.getNpcTemplate().get_size().equalsIgnoreCase("small")
				&& _weaponSmall > 0) {
			weaponMaxDamage = _weaponSmall;
		} else if (_targetNpc.getNpcTemplate().get_size().equalsIgnoreCase(
				"large")
				&& _weaponLarge > 0) {
			weaponMaxDamage = _weaponLarge;
		}

		int weaponDamage = 0;
		if (_weaponType == 58 && (_random.nextInt(100) + 1) <= 33) { // クリティカルヒット
			weaponDamage = weaponMaxDamage;
			_pc.sendPackets(new S_SkillSound(_pc.getId(), 3671));
			_pc.broadcastPacket(new S_SkillSound(_pc.getId(), 3671));
		} else if (_weaponType == 0) { // 素手
			weaponDamage = 0;
		} else {
			weaponDamage = _random.nextInt(weaponMaxDamage) + 1;
		}
		if (_pc.hasSkillEffect(SOUL_OF_FLAME)) {
			if (_weaponType != 20 && _weaponType != 62) {
				weaponDamage = weaponMaxDamage;
			}
		}

		int weaponTotalDamage = weaponDamage + _weaponAddDmg + _weaponEnchant;
		if (_pc.hasSkillEffect(DOUBLE_BRAKE)
				&& (_weaponType == 54 || _weaponType == 58)) {
			if ((_random.nextInt(100) + 1) <= 33) {
				weaponTotalDamage *= 2;
			}
		}

		weaponTotalDamage += calcMaterialBlessDmg(); // 銀祝福ダメージボーナス
		if (_weaponType == 54 && (_random.nextInt(100) + 1) <= 25) { // ダブルヒット
			weaponTotalDamage *= 2;
			_pc.sendPackets(new S_SkillSound(_pc.getId(), 3398));
			_pc.broadcastPacket(new S_SkillSound(_pc.getId(), 3398));
		}

		double dmg = weaponTotalDamage + _statusDamage + _pc.getDmgup();

		if (_pc.isKnight() || _pc.isDarkelf()) { // ナイト、DE
			if (_weaponType == 20 || _weaponType == 62) { // 弓、ガントトレットならクラスダメージボーナスなし
				dmg -= _pc.getBaseDmgup();
			}
		} else if (_pc.isElf()) { // エルフ
			if (_weaponType != 20 && _weaponType != 62) { // 弓、ガントトレット以外ならクラスダメージボーナスなし
				dmg -= _pc.getBaseDmgup();
			}
		}

		if (_weaponType == 20) { // 弓
			if (_arrow != null) {
				int add_dmg = 0;
				if (_targetNpc.getNpcTemplate().get_size().
						equalsIgnoreCase("large")) {
					add_dmg = _arrow.getItem().getDmgLarge();
				} else {
					add_dmg = _arrow.getItem().getDmgSmall();
				}
				if (add_dmg == 0) {
					add_dmg = 1;
				}
				if (_targetNpc.getNpcTemplate().is_hard()) {
					add_dmg /= 2;
				}
				dmg = dmg + _random.nextInt(add_dmg) + 1;
			} else if (_weaponId == 190) { // サイハの弓
				dmg = dmg + _random.nextInt(15) + 1;
			}
		} else if (_weaponType == 62) { // ガントトレット
			int add_dmg = 0;
			if (_targetNpc.getNpcTemplate().get_size().
					equalsIgnoreCase("large")) {
				add_dmg = _sting.getItem().getDmgLarge();
			} else {
				add_dmg = _sting.getItem().getDmgSmall();
			}
			if (add_dmg == 0) {
				add_dmg = 1;
			}
			dmg = dmg + _random.nextInt(add_dmg) + 1;
		}

		dmg = calcBuffDamage(dmg);

		dmg += calcWeaponSkillDamage();

		if (_weaponType == 0) { // 素手
			dmg = (_random.nextInt(5) + 4) / 4;
		}

		dmg -= calcNpcDamageReduction();

		if (_targetNpc instanceof L1PetInstance // プレイヤーからペット、サモンに攻撃
				|| _targetNpc instanceof L1SummonInstance) {
			dmg /= 8;
		}

		if (_targetNpc.hasSkillEffect(ICE_LANCE)) {
			dmg = 0;
		}
		if (_targetNpc.hasSkillEffect(EARTH_BIND)) {
			dmg = 0;
		}

		if (dmg <= 0) {
			_isHit = false;
		}

		return (int) dmg;
	}

	// ●●●● ＮＰＣ から プレイヤー へのダメージ算出 ●●●●
	private int calcNpcPcDamage() {
		int lvl = _npc.getLevel();
		double dmg = 0D;
		if (lvl < 10) {
			dmg = _random.nextInt(lvl) + 10D + _npc.getStr() / 2 + 1;
		} else {
			dmg = _random.nextInt(lvl) + _npc.getStr() / 2 + 1;
		}

		if (_npc instanceof L1PetInstance) {
			dmg += (lvl / 16); // ペットはLV16毎に追加打撃
		}

		dmg += _npc.getDmgup();

		if (isUndeadDamage()) {
			dmg *= 1.1;
		}

		dmg = dmg * getLeverage() / 10;

		dmg -= calcPcDefense();

		if (_npc.isWeaponBreaked()) { // ＮＰＣがウェポンブレイク中。
			dmg /= 2;
		}

		dmg -= _targetPc.getDamageReductionByArmor(); // 防具によるダメージ軽減

		if (_targetPc.hasSkillEffect(REDUCTION_ARMOR)) {
			int targetPcLvl = _targetPc.getLevel();
			if (targetPcLvl < 50) {
				targetPcLvl = 50;
			}
			dmg -= (targetPcLvl - 50) / 5 + 1;
		}
		if (_targetPc.hasSkillEffect(IMMUNE_TO_HARM)) {
			dmg /= 2;
		}
		if (_targetPc.hasSkillEffect(ABSOLUTE_BARRIER)) {
			dmg = 0;
		}
		if (_targetPc.hasSkillEffect(ICE_LANCE)) {
			dmg = 0;
		}
		if (_targetPc.hasSkillEffect(EARTH_BIND)) {
			dmg = 0;
		}

		if (_npc instanceof L1PetInstance || // ペット、サモンからプレイヤーに攻撃
				_npc instanceof L1SummonInstance) {
			dmg /= 8;
		}

		if (dmg <= 0) {
			_isHit = false;
		}

		addNpcPoisonAttack(_npc, _targetPc);

		return (int) dmg;
	}

	// ●●●● ＮＰＣ から ＮＰＣ へのダメージ算出 ●●●●
	private int calcNpcNpcDamage() {
		int lvl = _npc.getLevel();
		double dmg = 0;

		if (_npc instanceof L1PetInstance) {
			dmg = _random.nextInt(_npc.getNpcTemplate().get_level())
					+ _npc.getStr() / 2 + 1;
			dmg += (lvl / 16); // ペットはLV16毎に追加打撃
		} else {
			dmg = _random.nextInt(lvl) + _npc.getStr() / 2 + 1;
		}

		if (isUndeadDamage()) {
			dmg *= 1.1;
		}

		dmg = dmg * getLeverage() / 10;

		dmg -= calcNpcDamageReduction();

		if (_npc.isWeaponBreaked()) { // ＮＰＣがウェポンブレイク中。
			dmg /= 2;
		}

		addNpcPoisonAttack(_npc, _targetNpc);

		if (_targetNpc.hasSkillEffect(ICE_LANCE)) {
			dmg = 0;
		}
		if (_targetNpc.hasSkillEffect(EARTH_BIND)) {
			dmg = 0;
		}

		if (dmg <= 0) {
			_isHit = false;
		}

		return (int) dmg;
	}

	// ●●●● プレイヤーのダメージ強化魔法 ●●●●
	private double calcBuffDamage(double dmg) {
		if (_weaponType == 20 || _weaponType == 62) { // 弓かガントレットの場合、近接魔法分マイナス処理
			if (_pc.hasSkillEffect(FIRE_WEAPON)) {
				dmg -= 4;
			}
			if (_pc.hasSkillEffect(FIRE_BLESS)) {
				dmg -= 4;
			}
			if (_pc.hasSkillEffect(BURNING_WEAPON)) {
				dmg -= 6;
			}
		} else {
			if (_pc.hasSkillEffect(STORM_EYE)) {
				dmg -= 3;
			}
			if (_pc.hasSkillEffect(STORM_SHOT)) {
				dmg -= 5;
			}
		}

		// 火武器、バーサーカーのダメージは1.5倍しない
		if (_pc.hasSkillEffect(BURNING_SPIRIT)
				|| (_pc.hasSkillEffect(ELEMENTAL_FIRE) && _weaponType != 20 && _weaponType != 62)) {
			if ((_random.nextInt(100) + 1) <= 33) {
				double tempDmg = dmg;
				if (_pc.hasSkillEffect(FIRE_WEAPON)) {
					tempDmg -= 4;
				}
				if (_pc.hasSkillEffect(FIRE_BLESS)) {
					tempDmg -= 4;
				}
				if (_pc.hasSkillEffect(BURNING_WEAPON)) {
					tempDmg -= 6;
				}
				if (_pc.hasSkillEffect(BERSERKERS)) {
					tempDmg -= 5;
				}
				double diffDmg = dmg - tempDmg;
				dmg = tempDmg * 1.5 + diffDmg;
			}
		}

		return dmg;
	}

	// ●●●● プレイヤーのＡＣによるダメージ軽減 ●●●●
	private int calcPcDefense() {
		int ac = Math.max(0, 10 - _targetPc.getAc());
		int acDefMax = _targetPc.getClassFeature().getAcDefenseMax(ac);
		return _random.nextInt(acDefMax + 1);
	}

	// ●●●● ＮＰＣのダメージリダクションによる軽減 ●●●●
	private int calcNpcDamageReduction() {
		return _targetNpc.getNpcTemplate().get_damagereduction();
	}

	// ●●●● 武器の発動魔法判定 ●●●●
	private double calcWeaponSkillDamage() {
		double dmg = 0;
		int chance = _random.nextInt(100) + 1;
		if ((_weaponId == 54) && chance < 16) { // カーツ ソード
			dmg = 35 + _random.nextInt(25);
			_pc.sendPackets(new S_SkillSound(_targetId, 10));
			_pc.broadcastPacket(new S_SkillSound(_targetId, 10));
		} else if (_weaponId == 58 && chance < 8) { // デスナイト フレイムブレード
			dmg = 75 + _random.nextInt(15);
			_pc.sendPackets(new S_SkillSound(_targetId, 1811));
			_pc.broadcastPacket(new S_SkillSound(_targetId, 1811));
		} else if (_weaponId == 76 && chance < 16) { // ロンドゥ デュアルブレード
			dmg = 35 + _random.nextInt(25);
			_pc.sendPackets(new S_SkillSound(_targetId, 1805));
			_pc.broadcastPacket(new S_SkillSound(_targetId, 1805));
		} else if (_weaponId == 47 && chance < 2) { // サイレンス ソード
			_target.setSkillEffect(SILENCE, 16000);
			_pc.sendPackets(new S_SkillSound(_targetId, 2177));
			_pc.broadcastPacket(new S_SkillSound(_targetId, 2177));
		} else if (_weaponId == 121 && chance < 26) { // アイスクイーン スタッフ
			dmg = 95 + _random.nextInt(55);
			_pc.sendPackets(new S_SkillSound(_targetId, 1810));
			_pc.broadcastPacket(new S_SkillSound(_targetId, 1810));
		} else if (_weaponId == 124 && chance < 16) { // バフォメット スタッフ
			int mbounus = _pc.getMagicBonus();
			int mlev = _pc.getLevel() / 4;
			if (mlev > 10) {
				mlev = 10;
			}
			int sp = mbounus + mlev;
			int intel = _pc.getInt();
			int bskon = 0;
			if (_pc.hasSkillEffect(BERSERKERS)) {
				bskon = 2000;
			}
			double cor = 100 + (bskon + intel * 200) / 300;
			dmg = intel / 4 + sp * 3 * cor / 100
					+ _random.nextInt(sp * intel / 8 + 20);
			S_UseAttackSkill packet = new S_UseAttackSkill(_pc, _target, 129,
					false);
			_pc.sendPackets(packet);
			_pc.broadcastPacket(packet);
		} else if (_calcType == PC_PC
				&& (_weaponId == 2 || _weaponId == 200002)) { // ダイスダガー（PC→PC）
			int ddChance = _random.nextInt(100);
			if (ddChance > 97) { // 3%で発動
				_diceDaggerDamage = _targetPc.getCurrentHp() * 2 / 3;
				if (_targetPc.getCurrentHp() - dmg < 0) {
					_diceDaggerDamage = 0;
				}
				_diceDaggerEffect = true;
				String msg = weapon.getViewMessageName();
				_pc.sendPackets(new S_ServerMessage(158, msg));
				// \f1%0が蒸発してなくなりました。
				_pc.getInventory().removeItem(weapon, 1);
				_pc.getInventory().setEquipped(weapon, false);
				_pc.sendPackets(new S_CharVisualUpdate(_pc));
				_pc.sendPackets(new S_DeleteInventoryItem(_pc, weapon));
				_pc.getInventory().deleteItem(weapon);
				L1World.getInstance().removeObject(weapon);
				_pc.sendPackets(new S_OwnCharStatus(_pc));
			}
		}
		return dmg;
	}

	// ●●●● 武器の材質と祝福による追加ダメージ算出 ●●●●
	private int calcMaterialBlessDmg() {
		int damage = 0;
		int undead = _targetNpc.getNpcTemplate().get_undead();
		if ((_weaponMaterial == 14 || _weaponMaterial == 17 || _weaponMaterial == 22)
				&& (undead == 1 || undead == 3)) { // 銀・ミスリル・オリハルコン、かつ、アンデッド系・アンデッド系ボス
			damage += _random.nextInt(20) + 1;
		}
		if (_weaponBless == 0 && (undead == 1 || undead == 2 || undead == 3)) { // 祝福武器、かつ、アンデッド系・悪魔系・アンデッド系ボス
			damage += _random.nextInt(4) + 1;
		}
		return damage;
	}

	// ●●●● ＮＰＣのアンデッドの夜間攻撃力の変化 ●●●●
	private boolean isUndeadDamage() {
		boolean flag = false;
		int undead = _npc.getNpcTemplate().get_undead();
		boolean isNight = L1GameTimeClock.getInstance().getGameTime().isNight();
		if (isNight && (undead == 1 || undead == 3)) { // 18～6時、かつ、アンデッド系・アンデッド系ボス
			flag = true;
		}
		return flag;
	}

	// ●●●● ＮＰＣの毒攻撃を付加 ●●●●
	private void addNpcPoisonAttack(L1Character attacker, L1Character target) {
		if (_npc.getNpcTemplate().get_poisonatk() != 0) { // 毒攻撃あり
			if (15 >= _random.nextInt(100) + 1) { // 15%の確率で毒攻撃
				if (_npc.getNpcTemplate().get_poisonatk() == 1) { // 通常毒
					// 3秒周期でダメージ5
					L1DamagePoison.doInfection(attacker, target, 3000, 5);
				} else if (_npc.getNpcTemplate().get_poisonatk() == 2) { // 沈黙毒
					L1SilencePoison.doInfection(target);
				} else if (_npc.getNpcTemplate().get_poisonatk() == 4) { // 麻痺毒
					// 20秒後に45秒間麻痺
					L1ParalysisPoison.doInfection(target, 20000, 45000);
				}
			}
		} else if (_npc.getNpcTemplate().get_paralysisatk() != 0) { // 麻痺攻撃あり
		}
	}

	// ■■■■ マナスタッフと鋼鉄のマナスタッフのＭＰ吸収量算出 ■■■■
	public void calcStaffOfMana() {
		// SOMまたは鋼鉄のSOM
		if (_weaponId == 126 || _weaponId == 127) {
			int som_lvl = _weaponEnchant + 3; // 最大MP吸収量を設定
			if (som_lvl < 0) {
				som_lvl = 0;
			}
			// MP吸収量をランダム取得
			_drainMana = _random.nextInt(som_lvl) + 1;
			// 最大MP吸収量を9に制限
			if (_drainMana > Config.MANA_DRAIN_LIMIT_PER_SOM_ATTACK) {
				_drainMana = Config.MANA_DRAIN_LIMIT_PER_SOM_ATTACK;
			}
		}
	}

	// ■■■■ ＰＣの毒攻撃を付加 ■■■■
	public void addPcPoisonAttack(L1Character attacker, L1Character target) {
		int chance = _random.nextInt(100) + 1;
		if ((_weaponId == 13 || (_weaponId != 0 && _pc
				.hasSkillEffect(ENCHANT_VENOM)))
				&& chance <= 10) { // フィンガー オブ デス装備中、エンチャント ベノム中
			// 通常毒、3秒周期、ダメージHP-5
			L1DamagePoison.doInfection(attacker, target, 3000, 5);
		}
	}

	/* ■■■■■■■■■■■■■■ 攻撃モーション送信 ■■■■■■■■■■■■■■ */

	public void action() {
		if (_calcType == PC_PC || _calcType == PC_NPC) {
			actionPc();
		} else if (_calcType == NPC_PC || _calcType == NPC_NPC) {
			actionNpc();
		}
	}

	// ●●●● プレイヤーの攻撃モーション送信 ●●●●
	private void actionPc() {
		_pc.setHeading(_pc.targetDirection(_targetX, _targetY)); // 向きのセット
		if (_isHit) {
			if (_weaponType == 20) {
				if (_arrow != null) { // 矢がある場合
					_pc.sendPackets(new S_UseArrowSkill(_pc, _targetId, 66,
							_targetX, _targetY));
					_pc.broadcastPacket(new S_UseArrowSkill(_pc, _targetId, 66,
							_targetX, _targetY));
					_target.broadcastPacketExceptTargetSight(new S_DoActionGFX(
							_targetId, ActionCodes.ACTION_Damage), _pc);
					_pc.getInventory().removeItemOnlyInventory(_arrow, 1);
				} else if (_weaponId == 190) { // 矢が無くてサイハの場合
					_pc.sendPackets(new S_UseArrowSkill(_pc, _targetId, 2349,
							_targetX, _targetY));
					_pc.broadcastPacket(new S_UseArrowSkill(_pc, _targetId,
							2349, _targetX, _targetY));
					_target.broadcastPacketExceptTargetSight(new S_DoActionGFX(
							_targetId, ActionCodes.ACTION_Damage), _pc);
				}
			} else if (_weaponType == 62 && _sting != null) { // ガントレット
				_pc.sendPackets(new S_UseArrowSkill(_pc, _targetId, 2989,
						_targetX, _targetY));
				_pc.broadcastPacket(new S_UseArrowSkill(_pc, _targetId, 2989,
						_targetX, _targetY));
				_target.broadcastPacketExceptTargetSight(new S_DoActionGFX(
						_targetId, ActionCodes.ACTION_Damage), _pc);
				_pc.getInventory().removeItemOnlyInventory(_sting, 1);
			} else {
				_pc.sendPackets(new S_AttackStatus(_pc, _targetId,
						ActionCodes.ACTION_Attack));
				_pc.broadcastPacket(new S_AttackStatus(_pc, _targetId,
						ActionCodes.ACTION_Attack));
				_target.broadcastPacketExceptTargetSight(new S_DoActionGFX(
						_targetId, ActionCodes.ACTION_Damage), _pc);
			}
		} else {
			if (_weaponType == 20 && (_weaponId == 190 || _arrow != null)) {
				calcOrbit(_pc.getX(), _pc.getY(), _pc.getHeading()); // 軌道を計算
				if (_arrow != null) { // 矢がある場合
					_pc.sendPackets(new S_UseArrowSkill(_pc, 0, 66, _targetX,
							_targetY));
					_pc.broadcastPacket(new S_UseArrowSkill(_pc, 0, 66,
							_targetX, _targetY));
					_pc.getInventory().removeItemOnlyInventory(_arrow, 1);
				} else if (_weaponId == 190) { // 矢が無くてサイハの場合
					_pc.sendPackets(new S_UseArrowSkill(_pc, 0, 2349, _targetX,
							_targetY));
					_pc.broadcastPacket(new S_UseArrowSkill(_pc, 0, 2349,
							_targetX, _targetY));
				}
			} else if (_weaponType == 62 && _sting != null) { // ガントレット
				calcOrbit(_pc.getX(), _pc.getY(), _pc.getHeading()); // 軌道を計算
				_pc.sendPackets(new S_UseArrowSkill(_pc, 0, 2989, _targetX,
						_targetY));
				_pc.broadcastPacket(new S_UseArrowSkill(_pc, 0, 2989, _targetX,
						_targetY));
				_pc.getInventory().removeItemOnlyInventory(_sting, 1);
			} else {
				if (_targetId > 0) {
					_pc.sendPackets(new S_AttackMissPacket(_pc, _targetId));
					_pc.broadcastPacket(new S_AttackMissPacket(_pc, _targetId));
				} else {
					_pc.sendPackets(new S_AttackStatus(_pc, 0,
							ActionCodes.ACTION_Attack));
					_pc.broadcastPacket(new S_AttackStatus(_pc, 0,
							ActionCodes.ACTION_Attack));
				}
			}
		}
	}

	// ●●●● ＮＰＣの攻撃モーション送信 ●●●●
	private void actionNpc() {
		int _npcObjectId = _npc.getId();
		int bowActId = 0;
		int actId = 0;

		_npc.setHeading(_npc.targetDirection(_targetX, _targetY)); // 向きのセット

		// ターゲットとの距離が2以上あれば遠距離攻撃
		boolean isLongRange = (_npc.getLocation().getTileLineDistance(
				new Point(_targetX, _targetY)) > 1);
		bowActId = _npc.getNpcTemplate().getBowActId();

		if (getActId() > 0) {
			actId = getActId();
		} else {
			actId = ActionCodes.ACTION_Attack;
		}

		if (_isHit) {
			// 距離が2以上、攻撃者の弓のアクションIDがある場合は遠攻撃
			if (isLongRange && bowActId > 0) {
				_npc.broadcastPacket(new S_UseArrowSkill(_npc, _targetId,
						bowActId, _targetX, _targetY));
			} else {
				if (getGfxId() > 0) {
					_npc
							.broadcastPacket(new S_UseAttackSkill(_target,
									_npcObjectId, getGfxId(), _targetX,
									_targetY, actId));
					_target.broadcastPacketExceptTargetSight(new S_DoActionGFX(
							_targetId, ActionCodes.ACTION_Damage), _npc);
				} else {
					_npc.broadcastPacket(new S_AttackPacket(_target,
							_npcObjectId, actId));
					_target.broadcastPacketExceptTargetSight(new S_DoActionGFX(
							_targetId, ActionCodes.ACTION_Damage), _npc);
				}
			}
		} else {

			// 距離が2以上、攻撃者の弓のアクションIDがある場合は遠攻撃
			if (isLongRange && bowActId > 0) {
				_npc.broadcastPacket(new S_UseArrowSkill(_npc, 0, bowActId,
						_targetX, _targetY));
			} else {
				if (getGfxId() > 0) {
					_npc.broadcastPacket(new S_UseAttackSkill(_target,
							_npcObjectId, getGfxId(), _targetX, _targetY,
							actId, 0));
				} else {
					_npc.broadcastPacket(new S_AttackMissPacket(_npc,
							_targetId, actId));
				}
			}
		}
	}

	// 飛び道具（矢、スティング）がミスだったときの軌道を計算
	public void calcOrbit(int cx, int cy, int head) // 起点Ｘ 起点Ｙ 今向いてる方向
	{
		float dis_x = Math.abs(cx - _targetX); // Ｘ方向のターゲットまでの距離
		float dis_y = Math.abs(cy - _targetY); // Ｙ方向のターゲットまでの距離
		float dis = Math.max(dis_x, dis_y); // ターゲットまでの距離
		float avg_x = 0;
		float avg_y = 0;
		if (dis == 0) { // 目標と同じ位置なら向いてる方向へ真っ直ぐ
			if (head == 1) {
				avg_x = 1;
				avg_y = -1;
			} else if (head == 2) {
				avg_x = 1;
				avg_y = 0;
			} else if (head == 3) {
				avg_x = 1;
				avg_y = 1;
			} else if (head == 4) {
				avg_x = 0;
				avg_y = 1;
			} else if (head == 5) {
				avg_x = -1;
				avg_y = 1;
			} else if (head == 6) {
				avg_x = -1;
				avg_y = 0;
			} else if (head == 7) {
				avg_x = -1;
				avg_y = -1;
			} else if (head == 0) {
				avg_x = 0;
				avg_y = -1;
			}
		} else {
			avg_x = dis_x / dis;
			avg_y = dis_y / dis;
		}

		int add_x = (int) Math.floor((avg_x * 15) + 0.59f); // 上下左右がちょっと優先な丸め
		int add_y = (int) Math.floor((avg_y * 15) + 0.59f); // 上下左右がちょっと優先な丸め

		if (cx > _targetX) {
			add_x *= -1;
		}
		if (cy > _targetY) {
			add_y *= -1;
		}

		_targetX = _targetX + add_x;
		_targetY = _targetY + add_y;
	}

	/* ■■■■■■■■■■■■■■■ 計算結果反映 ■■■■■■■■■■■■■■■ */

	public void commit() {
		if (_isHit) {
			if (_calcType == PC_PC || _calcType == NPC_PC) {
				commitPc();
			} else if (_calcType == PC_NPC || _calcType == NPC_NPC) {
				commitNpc();
			}
		}

		// ダメージ値及び命中率確認用メッセージ
		if (!Config.ALT_ATKMSG) {
			return;
		}
		if (Config.ALT_ATKMSG) {
			if ((_calcType == PC_PC || _calcType == PC_NPC)
					&& _pc.getAccessLevel() != 200) {
				return;
			}
			if ((_calcType == PC_PC || _calcType == NPC_PC)
					&& _targetPc.getAccessLevel() != 200) {
				return;
			}
		}
		String msg0 = "";
		String msg1 = "に";
		String msg2 = "";
		String msg3 = "";
		String msg4 = "";
		if (_calcType == PC_PC || _calcType == PC_NPC) { // アタッカーがＰＣの場合
			msg0 = _pc.getName();
		} else if (_calcType == NPC_PC) { // アタッカーがＮＰＣの場合
			msg0 = _npc.getName();
		}

		if (_calcType == NPC_PC || _calcType == PC_PC) { // ターゲットがＰＣの場合
			msg4 = _targetPc.getName();
			msg2 = "HitR" + _hitRate + "% THP" + _targetPc.getCurrentHp();
		} else if (_calcType == PC_NPC) { // ターゲットがＮＰＣの場合
			msg4 = _targetNpc.getName();
			msg2 = "Hit" + _hitRate + "% Hp" + _targetNpc.getCurrentHp();
		}
		msg3 = _isHit ? _damage + "与えた" : "ミスしました";

		if (_calcType == PC_PC || _calcType == PC_NPC) { // アタッカーがＰＣの場合
			_pc.sendPackets(new S_ServerMessage(166, msg0, msg1, msg2, msg3,
					msg4)); // \f1%0が%4%1%3 %2
		}
		if (_calcType == NPC_PC || _calcType == PC_PC) { // ターゲットがＰＣの場合
			_targetPc.sendPackets(new S_ServerMessage(166, msg0, msg1, msg2,
					msg3, msg4)); // \f1%0が%4%1%3 %2
		}
	}

	// ●●●● プレイヤーに計算結果を反映 ●●●●
	private void commitPc() {
		if (_calcType == PC_PC) {
			if (_drainMana > 0 && _targetPc.getCurrentMp() > 0) {
				if (_drainMana > _targetPc.getCurrentMp()) {
					_drainMana = _targetPc.getCurrentMp();
				}
				short newMp = (short) (_targetPc.getCurrentMp() - _drainMana);
				_targetPc.setCurrentMp(newMp);
				newMp = (short) (_pc.getCurrentMp() + _drainMana);
				_pc.setCurrentMp(newMp);
			}
			damagePcWeaponDurability(); // 武器を損傷させる。
			_targetPc.receiveDamage(_pc, _damage);
		} else if (_calcType == NPC_PC) {
			_targetPc.receiveDamage(_npc, _damage);
		}
	}

	// ●●●● ＮＰＣに計算結果を反映 ●●●●
	private void commitNpc() {
		if (_calcType == PC_NPC) {
			if (_drainMana > 0) {
				int drainValue = _targetNpc.drainMana(_drainMana);
				int newMp = _pc.getCurrentMp() + drainValue;
				_pc.setCurrentMp(newMp);

				if (drainValue > 0) {
					int newMp2 = _targetNpc.getCurrentMp() - drainValue;
					_targetNpc.setCurrentMpDirect(newMp2);
				}
			}

			damageNpcWeaponDurability(); // 武器を損傷させる。
			_targetNpc.receiveDamage(_pc, _damage);
		} else if (_calcType == NPC_NPC) {
			_targetNpc.receiveDamage(_npc, _damage);
		}
	}

	/* ■■■■■■■■■■■■■■■ カウンターバリア ■■■■■■■■■■■■■■■ */

	// ■■■■ カウンターバリア時の攻撃モーション送信 ■■■■
	public void actionCounterBarrier() {
		if (_calcType == PC_PC) {
			_pc.setHeading(_pc.targetDirection(_targetX, _targetY)); // 向きのセット
			_pc.sendPackets(new S_AttackMissPacket(_pc, _targetId));
			_pc.broadcastPacket(new S_AttackMissPacket(_pc, _targetId));
			_pc.sendPackets(new S_DoActionGFX(_pc.getId(),
					ActionCodes.ACTION_Damage));
			_pc.broadcastPacket(new S_DoActionGFX(_pc.getId(),
					ActionCodes.ACTION_Damage));
		} else if (_calcType == NPC_PC) {
			int actId = 0;
			_npc.setHeading(_npc.targetDirection(_targetX, _targetY)); // 向きのセット
			if (getActId() > 0) {
				actId = getActId();
			} else {
				actId = ActionCodes.ACTION_Attack;
			}
			if (getGfxId() > 0) {
				_npc
						.broadcastPacket(new S_UseAttackSkill(_target, _npc
								.getId(), getGfxId(), _targetX, _targetY,
								actId, 0));
			} else {
				_npc.broadcastPacket(new S_AttackMissPacket(_npc, _targetId,
						actId));
			}
			_npc.broadcastPacket(new S_DoActionGFX(_npc.getId(),
					ActionCodes.ACTION_Damage));
		}
	}

	// ■■■■ 相手の攻撃に対してカウンターバリアが有効かを判別 ■■■■
	public boolean isShortDistance() {
		boolean isShortDistance = true;
		if (_calcType == PC_PC) {
			if (_weaponType == 20 || _weaponType == 62) { // 弓かガントレット
				isShortDistance = false;
			}
		} else if (_calcType == NPC_PC) {
			boolean isLongRange = (_npc.getLocation().getTileLineDistance(
					new Point(_targetX, _targetY)) > 1);
			int bowActId = _npc.getNpcTemplate().getBowActId();
			// 距離が2以上、攻撃者の弓のアクションIDがある場合は遠攻撃
			if (isLongRange && bowActId > 0) {
				isShortDistance = false;
			}
		}
		return isShortDistance;
	}

	// ■■■■ カウンターバリアのダメージを反映 ■■■■
	public void commitCounterBarrier() {
		int damage = calcCounterBarrierDamage();
		if (damage == 0) {
			return;
		}
		if (_calcType == PC_PC) {
			_pc.receiveDamage(_targetPc, damage);
		} else if (_calcType == NPC_PC) {
			_npc.receiveDamage(_targetPc, damage);
		}
	}

	// ●●●● カウンターバリアのダメージを算出 ●●●●
	private int calcCounterBarrierDamage() {
		int damage = 0;
		L1ItemInstance weapon = null;
		weapon = _targetPc.getWeapon();
		int weaponType = weapon.getItem().getType1();
		if (weapon != null && weaponType == 50) { // 両手剣
			// (BIG最大ダメージ+強化数+追加ダメージ)*2
			damage = (weapon.getItem().getDmgLarge() + weapon.getEnchantLevel() + weapon
					.getItem().getDmgModifier()) * 2;
		}
		return damage;
	}

	/*
	 * 武器を損傷させる。 対NPCの場合、損傷確率は10%とする。祝福武器は3%とする。
	 */
	private void damageNpcWeaponDurability() {
		int chance = 10;
		int bchance = 3;
		String msg0 = "";

		/*
		 * 損傷しないNPC、素手、損傷しない武器使用の場合何もしない。
		 */
		if (_calcType != PC_NPC
				|| _targetNpc.getNpcTemplate().is_hard() == false
				|| _weaponType == 0 || weapon.getItem().get_canbedmg() == 0) {
			return;
		}
		// 通常の武器・呪われた武器
		if ((_weaponBless == 1 || _weaponBless == 2)
				&& ((_random.nextInt(100) + 1) < chance)) {
			msg0 = weapon.getViewMessageName();
			// \f1あなたの%0が損傷しました。
			_pc.sendPackets(new S_ServerMessage(268, msg0));
			_pc.getInventory().receiveDamage(weapon);
		}
		// 祝福された武器
		if (_weaponBless == 0 && ((_random.nextInt(100) + 1) < bchance)) {
			msg0 = weapon.getViewMessageName();
			// \f1あなたの%0が損傷しました。
			_pc.sendPackets(new S_ServerMessage(268, msg0));
			_pc.getInventory().receiveDamage(weapon);
		}
	}

	/*
	 * バウンスアタックにより武器を損傷させる。 バウンスアタックの損傷確率は10%
	 */
	private void damagePcWeaponDurability() {
		// PvP以外、素手、弓、ガントトレット、バウンスアタックの未使用の場合何もしない
		if (_calcType != PC_PC || _weaponType == 0 || _weaponType == 20
				|| _weaponType == 62
				|| _targetPc.hasSkillEffect(BOUNCE_ATTACK) == false) {
			return;
		}

		if (_random.nextInt(100) + 1 <= 10) {
			String msg0 = weapon.getViewMessageName();
			// \f1あなたの%0が損傷しました。
			_pc.sendPackets(new S_ServerMessage(268, msg0));
			_pc.getInventory().receiveDamage(weapon);
		}
	}
}
